package edu.hawaii.duedates.tests;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.fail;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.junit.Ignore;
import org.junit.Test;

import edu.hawaii.duedates.BookInfoRecord;
import edu.hawaii.duedates.CommandLineArgs;
import edu.hawaii.duedates.DueDates;
import edu.hawaii.duedates.HiStateLibrary;
import edu.hawaii.duedates.UniversityOfHawaiiLibrary;

/**
 * TestDuesDates is a unit test for the DueDates class that checks for valid user input.
 * The test includes a check for the within option. 
 * 
 * @author Team Purple John Ancheta Daniel Arakaki Mari-Lee Flestado
 * @version 1.1, October 14, 2008
 */
public class TestDueDates {

  /**A String for the uhm option. */
  public static final String UHM_OPTION = "-uhm";
  
  /**A String for the uhm option. */
  public static final String EMAIL_OPTION = "-email";
  
  /** Unexpected error fail string.*/
  public static final String SHOULD_NOT_FAIL = "Should not fail.";
  
  /** Instance variable for user id, instantiated to take in command argument. */
  private static final String dueDatesTestUser1Id = System.getenv("DUEDATES_TESTUSER1_ID");

  /** Instance variable for user last name, instantiated to take in command argument. */
  private static final String dueDatesTestUser1LastName = 
                              System.getenv("DUEDATES_TESTUSER1_LASTNAME");
  
  /** Instance variable for user id, instantiated to take in command argument. */
  private static final String dueDatesTestUser2Id = 
                              System.getenv("DUEDATES_TESTUSER2_ID");

  /** Instance variable for user last name, instantiated to take in command argument. */
  private static final String dueDatesTestUser2LastName = 
                              System.getenv("DUEDATES_TESTUSER2_LASTNAME");
  
  /** Instance variable for user last name, instantiated to take in command argument. */
  private static final String CONSOLE_OPTION = "-console";
  
  /** Instance variable for the arrayList bookList.*/
  private static List<BookInfoRecord> bookList = new ArrayList<BookInfoRecord>();

  /**
   * Tests withinBookList option with ndaysTillDue = 0.
   *
   * @throws Exception This should not happen.
   */
  @Test
  public void testWithinBookListWithDefaultZero() throws Exception {
    CommandLineArgs commandLineArgs = new CommandLineArgs();
    commandLineArgs.parse(new String[] {CONSOLE_OPTION, UHM_OPTION,
                                        dueDatesTestUser2Id,
                                        dueDatesTestUser2LastName});
    DueDates dueDate = new DueDates();
    dueDate.set(commandLineArgs);
    UniversityOfHawaiiLibrary uhmLib = new UniversityOfHawaiiLibrary();
    uhmLib.getUhmInfo(dueDatesTestUser2Id, dueDatesTestUser2LastName, bookList);
    List<BookInfoRecord> bookList = new ArrayList<BookInfoRecord>();
    List<BookInfoRecord> withinBookList = dueDate.getWithinBookList(0, bookList);
    assertSame("Should reference the same bookList", withinBookList, bookList); 
  }
  
  /**
   * Tests withinBookList option with ndaysTillDue = 10.
   *
   * @throws Exception This should not happen.
   */
  @Test
  public void testWithinBookListWithPositiveValue() throws Exception {
    CommandLineArgs commandLineArgs = new CommandLineArgs();
    commandLineArgs.parse(new String[] {CONSOLE_OPTION, UHM_OPTION,
                                        dueDatesTestUser2Id,
                                        dueDatesTestUser2LastName});
    DueDates dueDate = new DueDates();
    dueDate.set(commandLineArgs);
    UniversityOfHawaiiLibrary uhmLib = new UniversityOfHawaiiLibrary();
    List<BookInfoRecord> bookList = new ArrayList<BookInfoRecord>();
    uhmLib.getUhmInfo(dueDatesTestUser2Id, dueDatesTestUser2LastName, bookList);
    List<BookInfoRecord> withinBookList = dueDate.getWithinBookList(10, bookList);
    boolean b = (withinBookList == null); 
    assertFalse("Should not be null.", b);
  }
  
  /**
   * Test with only -uhm options.
   */
  @Test 
  public void testOnlyValidUhmOptions() {
    CommandLineArgs commandLineArgs = new CommandLineArgs();
    try {
      commandLineArgs.parse(new String[] {CONSOLE_OPTION, UHM_OPTION,
                                          dueDatesTestUser2Id,
                                          dueDatesTestUser2LastName});
      DueDates dueDates = new DueDates();
      dueDates.set(commandLineArgs);
      dueDates.getSiteInfo();
    }
    catch (Exception e) {
      e.printStackTrace();
      fail(SHOULD_NOT_FAIL);
    }
  }
  /**
   * Test with only -uhm options.
   *
   * @throws Exception This should  happen.
   */
  @Test (expected = Exception.class)
  public void testOnlyNoBooksCheckout() throws Exception {
    UniversityOfHawaiiLibrary uhm = new UniversityOfHawaiiLibrary();
    List<BookInfoRecord> bookList = new ArrayList<BookInfoRecord>();
    uhm.getUhmInfo("fakeusername", "fakelastname", bookList);
  }
  /**
   * Test with valid -uhm account and sort.
   */
  @Test 
  public void testOnlyValidUhmOptionsWithSortDueDate() {
    CommandLineArgs commandLineArgs = new CommandLineArgs();
    try {
      commandLineArgs.parse(new String[] {CONSOLE_OPTION, "-sort", 
                                          "duedate", 
                                          UHM_OPTION, 
                                          dueDatesTestUser2Id,
                                          dueDatesTestUser2LastName});
      DueDates dueDates = new DueDates();
      dueDates.set(commandLineArgs);
      dueDates.getSiteInfo();
    }
    catch (Exception e) {
      e.printStackTrace();
      fail(SHOULD_NOT_FAIL);
    }
  }
  
  /**
   * Test with valid -uhm account and within.
   */
  @Test 
  public void testOnlyValidUhmOptionsWithinOneDay() {
    CommandLineArgs commandLineArgs = new CommandLineArgs();
    try {
      commandLineArgs.parse(new String[] {CONSOLE_OPTION, "-within", 
                                          "1", 
                                          UHM_OPTION, 
                                          dueDatesTestUser1Id,
                                          dueDatesTestUser1LastName});
      DueDates dueDates = new DueDates();
      dueDates.set(commandLineArgs);
      dueDates.getSiteInfo();
   }
   catch (Exception e) {
     e.printStackTrace();
     fail(SHOULD_NOT_FAIL);
   }
  }
  
  /**
   * Test with valid -uhm account and within.
   */
  @Test 
  public void testOnlyValidUhmOptionsWithinOneThousandDays() {
    CommandLineArgs commandLineArgs = new CommandLineArgs();
    try {
      commandLineArgs.parse(new String[] {CONSOLE_OPTION, "-within", 
                                          "10000", 
                                          UHM_OPTION, 
                                          dueDatesTestUser2Id,
                                          dueDatesTestUser2LastName});
      DueDates dueDates = new DueDates();
      dueDates.set(commandLineArgs);
      dueDates.getSiteInfo();
   }
   catch (Exception e) {
     e.printStackTrace();
     fail(SHOULD_NOT_FAIL);
   }
  }
  
  /**
   * Test with valid -uhm account and within.
   *
   * @throws Exception This should not happen.
   */
  @Test 
  public void testWithinWithPastDueBooks() throws Exception {
      DueDates dueDates = new DueDates();
      List<BookInfoRecord> bookList = new ArrayList<BookInfoRecord>();
      bookList.add(new BookInfoRecord(new Date(0), "bookRecord", "uhm"));
      List<BookInfoRecord> withinBookList = dueDates.getWithinBookList(1, bookList);
      assertEquals("Should be Equal", bookList, withinBookList);
  }
  
  /**
   * Tests for the user's valid ID for Hawaii State library.
   * 
   * @throws Exception An exception is thrown should a user not enter the right id.
   */
  @Test(expected = Exception.class)
  public void testHslGetValidLastName() throws Exception {
    HiStateLibrary hiState = new HiStateLibrary();
    String sLastName = null;
   
    hiState.getHawaiiStateInfo(dueDatesTestUser1Id, sLastName, bookList);
    assertFalse("This should be false", dueDatesTestUser1LastName.equals(sLastName));
    assertEquals("The length should be equal", 4, dueDatesTestUser1LastName.length());
    
  }
  
  /**
   * Tests for the user's valid ID for Hawaii State library.
   * 
   * @throws Exception An exception is thrown should a user not enter the right id.
   */
  @Test(expected = Exception.class)
  public void testHslGetValidId() throws Exception {
    HiStateLibrary hiState = new HiStateLibrary();
    String sId = null;
    
    hiState.getHawaiiStateInfo(dueDatesTestUser1Id, sId, bookList);
    assertFalse("This should be equal", dueDatesTestUser1LastName.equals(sId));
     
  }
  
  /**
   * Test for getting HSL information.
   * 
   * @throws Exception An exception is thrown should a user not enter valid information.
   */
  public void testGetHawaiiStateInfo() throws Exception {
    HiStateLibrary hiState = new HiStateLibrary();
    CommandLineArgs args = new CommandLineArgs();
    String anId = "1234567890";
    String sPassWord = "1234";
    
    hiState.getHawaiiStateInfo(args.getHslId(),args.getHslLastFourDigitsForPhoneNumber(),bookList);
    // check for state id length
    assertEquals("This should be equal", args.getHslId().length(), anId.length());
    // check for password length
    assertEquals("This should be equal", args.getHslLastFourDigitsForPhoneNumber()
        .length(), sPassWord.length());
    assertSame("Testing id length", args.getHslId().length(), anId.length());
    assertSame("Testing id length", args.getHslLastFourDigitsForPhoneNumber().length(), sPassWord
        .length());
    hiState.getHawaiiStateInfo(anId, sPassWord, bookList);
  }
  /**
   * Test with only -hsl options.
   */
  @Ignore
  @Test 
  public void testOnlyValidHslOptions() {
    CommandLineArgs commandLineArgs = new CommandLineArgs();
    try {
      commandLineArgs.parse(new String[] {CONSOLE_OPTION, 
                                          "-hsl", dueDatesTestUser2Id, dueDatesTestUser2LastName});
      DueDates dueDates = new DueDates();
      dueDates.set(commandLineArgs);
      dueDates.getSiteInfo();
    }
    catch (Exception e) {
      e.printStackTrace();
      fail(SHOULD_NOT_FAIL);
    }
  }
  
  /**
   * Test with only -uhm options.
   */
  @Test 
  public void testOnlyInvalidUhmOptions() {
    CommandLineArgs commandLineArgs = new CommandLineArgs();
    try {
      commandLineArgs.parse(new String[] {CONSOLE_OPTION, 
                                          "-uhm", dueDatesTestUser2Id, "fakelastname"});
      DueDates dueDates = new DueDates();
      dueDates.set(commandLineArgs);
      dueDates.run();
    }
    catch (Exception e) {
      e.printStackTrace();
      fail(SHOULD_NOT_FAIL);
    }
  }
  
  /**
   * Test with only -uhm options.
   */
  @Test 
  public void testOnlyInvalidUhmOptionsVerbose() {
    CommandLineArgs commandLineArgs = new CommandLineArgs();
    try {
      commandLineArgs.parse(new String[] {"-verbose", CONSOLE_OPTION, 
                                          "-uhm", dueDatesTestUser2Id, "fakelastname"});
      DueDates dueDates = new DueDates();
      dueDates.set(commandLineArgs);
      dueDates.run();
    }
    catch (Exception e) {
      e.printStackTrace();
      fail(SHOULD_NOT_FAIL);
    }
  }
  
  /**
   * Only used to improve coverage with Emma.
   */
  @Test
  public void testMainWithNoArguments() {
    try {
      DueDates.main(null);
    }
    catch (Exception e) {
      fail(SHOULD_NOT_FAIL);
    }
  }
  
  /**
   * Only used to improve coverage with Emma.
   */
  @Test
  public void testMainWithValidUhmAccount() {
    try {
      DueDates.main(new String[] {
               CONSOLE_OPTION, UHM_OPTION, dueDatesTestUser2Id, dueDatesTestUser2LastName});
    }
    catch (Exception e) {
      fail(SHOULD_NOT_FAIL);
    }
  }
  
  /**
   * Only used to improve coverage with Emma.
   */
  @Test
  public void testMainWithValidUhmAccountAndEmailOption() {
    try {
      DueDates.main(new String[] {
               EMAIL_OPTION, 
               "myemailadress", "mysmtpserver", 
               UHM_OPTION, dueDatesTestUser2Id, dueDatesTestUser2LastName});
    }
    catch (Exception e) {
      fail(SHOULD_NOT_FAIL);
    }
  }
  
  /**
   * Only used to improve coverage with Emma.
   */
  @Test
  public void testMainWithVerboseAndInvalidLogin() {
    try {
      DueDates.main(new String[] {"-verbose", UHM_OPTION, "invalidId", "invalidLastName"});   
    }
    catch (Exception e) {
      fail(SHOULD_NOT_FAIL);
    }
  }
  /**
   * Only used to improve coverage with Emma.
   */
  @Test
  public void testMainWithVerboseWakeupAndInvalidLogin() {
    try {
      DueDates.main(new String[] {"-verbose", "-console", "-wakeup",
                                  "1", UHM_OPTION, "invalidId", "invalidLastName"});
    }
    catch (Exception e) {
      fail(SHOULD_NOT_FAIL);
    }
  }

  /**
   * Only used to improve coverage with Emma.
   */
  @Test
  public void testMainWithInvalidLogin() {
    try {
      DueDates.main(new String[] {UHM_OPTION, "invalidId", "invalidLastName"});   
    }
    catch (Exception e) {
      fail(SHOULD_NOT_FAIL);
    }
  }
}
